﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFit.Core.Interfaces;
using System.Reflection;
using log4net;

namespace NFit.Core.Config
{
    /// <summary>
    /// Singleton for hosting NFit configuration
    /// </summary>
    [Serializable]
    public class NFitConfiguration
    {
        private static ILog Logger = log4net.LogManager.GetLogger(typeof(NFitConfiguration));

        private IList<ISpecificationDataSource> _datasources = new List<ISpecificationDataSource>();
        /// <summary>
        /// The list of data sources
        /// </summary>
        public IList<ISpecificationDataSource> Datasources
        {
            get { return _datasources; }
            set { _datasources = value; }
        }

        private IList<Assembly> _fixtureAssemblies = new List<Assembly>();

        /// <summary>
        /// The list of assemblies containing fixtures
        /// </summary>
        public IList<Assembly> FixtureAssemblies
        {
            get { return _fixtureAssemblies; }
            set { _fixtureAssemblies = value; }
        }

        private IList<IReportWriter> _writers = new List<IReportWriter>();
        
        /// <summary>
        /// The report writer for this configuration
        /// </summary>
        public IList<IReportWriter> Writers
        {
            get { return _writers; }
            set { _writers = value; }
        }

        /// <summary>
        /// Add configuration entries to the current configuration
        /// </summary>
        /// <param name="configurator"></param>
        public void Configure(INFitConfigurator configurator)
        {
            foreach(var datasource in configurator.GetDatasources())
            {
                Datasources.Add(datasource);
            }

            foreach (var ass in configurator.GetFixtureAssemblies())
            {
                FixtureAssemblies.Add(ass);
            }

            foreach (var writer in configurator.GetWriters())
            {
                Writers.Add(writer);
            }
        }

        /// <summary>
        /// Add configuration from the App.config file
        /// </summary>
        public void ReadAppConfig()
        {
            Configure(new Xml.XmlConfigurator());
        }

        /// <summary>
        /// Add configuration from the App.config file
        /// </summary>
        public void ReadConfig(string fileName)
        {
            Configure(new Xml.XmlConfigurator(fileName));
        }

        /// <summary>
        /// Search all assemblies in the AppDomain to find fixtures
        /// </summary>
        public void SearchFixtureAssemblies()
        {
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

            foreach (var ass in assemblies)
            {
                Logger.Debug("Inspecting assembly " + ass.FullName);

                try
                {
                    Type[] types = ass.GetTypes();
                    foreach (var type in types)
                    {
                        if (type.IsAFixtureImplementation() || type.IsATestImplementation())
                        {
                            if (!FixtureAssemblies.Contains(ass))
                            {
                                Logger.Debug("Adding assembly " + ass.FullName);

                                FixtureAssemblies.Add(ass);
                            }
                            break;                            
                        }
                    }
                }
                catch
                {
                }
            }
        }
    }
}
